import { any, areTypedArraysEqual } from "../../core/logic";
import { ComponentType } from "../Component";
import { Light } from "./Light";
import { color } from "../../core/color";
import { mat4, vec3 } from '../../core/math/wgpu-matrix.module';
import { Buffer } from "../../gpu/types/Buffer";
import { Evented, Event, EventType } from "../../event/index";
/**
 * 平行光
 * @class 
 * @extends w.light.Light
 * @memberof w.light
 */
class DirectionLight extends Light {
  /**
   * @constructor
   * @param {Array} opts.at 【可选,缺省:[0,0,0]】 平行光的at点，平行光的方向由position和at构成。
   * @param {Boolean} opts.cast 【可选,缺省:false】是否投射阴影。
   * @example
   * let light=new w.light.DirectionLight({at:[0,0,0],cast:fase,intensty:1.0,color:"#ffffff"});
   */
  constructor(opts = {}) {
    opts.type = any(opts.type, ComponentType.DirectionLight);
    super(opts);
    this.lightbuffer = [];
    this.lightType = 3;
    this._at = any(opts.at, [0, 0, 0]);
    this.cast = any(opts.cast, false);
    this.setState(true);
    this.autoUpdate = true;
    this._shadowLeft = any(opts.shadowLeft, -800);
    this._shadowRight = any(opts.shadowRight, 800);
    this._shadowTop = any(opts.shadowTop, 800);
    this._shadowBottom = any(opts.shadowBottom, -800);
    this._shadowNear = any(opts.shadowNear, -500);
    this._shadowFar = any(opts.shadowFar, 500);
    this._shadowBias = any(opts.shadowBias, 0.0007)
    this._shadowIntensity = any(opts.shadowIntensity, 1.0)
    this.initShadow()
    this.update();
  }
  /**
   * @property {w.component.Trans} 平行光的trans属性。
   * @readonly
   */
  get trans() {
    if (!this.at) {
      this.at = [this._trans.position.x, this._trans.position.y, 0];
    }
    return this._trans;
  }
  /**
   * @property {Array} 平行光的at属性。
   */
  set at(v) {
    if (v && !areTypedArraysEqual(this.at, v)) {
      this._at = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightBuffer");
      this.update();
      return this;
    }
  }
  get at() {
    return this._at;
  }
  get cast() {
    return this._cast;
  }
  /**
   * @property {Array} 平行光的cast属性。
   */
  set cast(v) {
    this._cast = v;
    this.setState(false, "lightCameraBuffer");
    if (v) {
      this.initShadow()
    }
    this.update();
    return;
  }
  get shadowLeft() {
    return this._shadowLeft;
  }
  /**
   * @property {Number} 阴影左边范围。
   */
  set shadowLeft(v) {
    if (v && v != this.shadowLeft) {
      this._shadowLeft = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowRight() {
    return this._shadowRight;
  }
  /**
   * @property {Number} 阴影右边范围。
   */
  set shadowRight(v) {
    if (v && v != this.shadowLeft) {
      this._shadowRight = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowTop() {
    return this._shadowTop;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowTop(v) {
    if (v && v != this.shadowLeft) {
      this._shadowTop = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowBottom() {
    return this._shadowBottom;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowBottom(v) {
    if (v && v != this.shadowLeft) {
      this._shadowBottom = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowNear() {
    return this._shadowNear;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowNear(v) {
    if (v && v != this.shadowLeft) {
      this._shadowNear = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowFar() {
    return this._shadowFar;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowFar(v) {
    if (v && v != this.shadowLeft) {
      this._shadowFar = v;
      this.inputShadowData()
      let ev = new Event(EventType.ShadowUpdate)
      this.publish(ev);//抛出舞台改变事件
      this.setState(false, "lightCameraBuffer");
      this.update();
      return this;
    }
    return;
  }
  get shadowBias() {
    return this._shadowBias;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowBias(v) {
    this._shadowBias = v;
    this.setState(false, "lightCameraBuffer");
    this.update();
    return;
  }
  get shadowIntensity() {
    return this._shadowIntensity;
  }
  /**
   * @property {Number} 阴影上边范围。
   */
  set shadowIntensity(v) {
    this._shadowIntensity = v;
    this.setState(false, "lightCameraBuffer");
    this.update();
    return;
  }
  initShadow() {
    if (this.cast) {
      if (!this.shadowBuffer) {
        this.shadowBuffer = new Buffer({
          id: "SingleLightCamera",
          name: "SingleLightCamera",
          usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
          visibility: GPUShaderStage.VERTEX,
          type: "uniform",
          size: 64,
          data: new Float32Array(16),
        });
      }
    }
  }
  inputShadowData() {
    this.lightViewProj = this.getViewProj();
    let vp = new Float32Array(this.lightViewProj)
    this.shadowBuffer.buffer(vp)
  }
  getViewProj() {
    if (this.cast) {
      const lightPosition = vec3.fromValues(...this.trans.position);
      const upVector = vec3.fromValues(0, 1, 0);
      const origin = vec3.fromValues(...this.at);
      const lightViewMatrix = mat4.lookAt(lightPosition, origin, upVector)
      const lightProjectionMatrix = mat4.ortho(this.shadowLeft, this.shadowRight, this.shadowBottom, this.shadowTop, this.shadowNear, this.shadowFar);
      const lightViewProjMatrix = mat4.multiply(lightProjectionMatrix, lightViewMatrix);
      let data = [];
      data.push(...Array.from(lightViewProjMatrix))
      return data
    }
  }
  getLightBuffer() {
    if (!this.getState("lightBuffer")) {
      let _color = color.format(this.color, false);
      let shadowIntensity = (-1 * this.shadowIntensity) + 1
      this.lightbuffer = [
        ..._color, //0-2
        this.lightType, //3 类型
        ...this.trans.position, //4-6 位置或方向
        this.intensity, //7 强度
        ...this.at, //8-10 距离
        0, //11 innerRad
        Number(this.cast), //12 innerRad|width
        this.shadowBias, //13 outerRad|height
        shadowIntensity,//14 
        0//15
      ];
      this.setState(true, "lightBuffer");
      if (this.cast) {
        this.lightViewProj = this.getViewProj();
        this.lightbuffer.push(...this.lightViewProj)
        let vp = new Float32Array(this.lightViewProj)
        this.shadowBuffer.buffer(vp)
        this.setState(true, "lightCameraBuffer");
      }

    }
    return this.lightbuffer;
  }
}
export { DirectionLight };
